﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using ProdControls.NativePatterns.MessageConstants;
using ProdControls.Utility;

namespace ProdControls
{
    /// <summary>
    ///   Provides methods to interact with ListBox controls using the Win32 API
    /// </summary>
    internal static class ProdListBoxNative
    {
        private const int LB_ERR = -1;

        /// <summary>
        ///   Uses SendMessage to get # of items in ListBox
        /// </summary>
        /// <param name="windowHandle"> Handle to the control </param>
        /// <returns> Number of items in the list box </returns>
        internal static int GetItemCountNative(IntPtr windowHandle)
        {
            try
            {
                int retVal = (int) NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_GETCOUNT, 0, 0);
                return retVal;
            }
            catch (Exception)
            {
                return LB_ERR;
            }
        }

        /// <summary>
        ///   Uses SendMessage to get the number of selected items from a multi-select listbox
        /// </summary>
        /// <param name="windowHandle"> handle to listbox </param>
        /// <returns> number of selected items </returns>
        /// <remarks>
        ///   This will FAIL on a single select
        /// </remarks>
        internal static int GetSelectedItemCountNative(IntPtr windowHandle)
        {
            try
            {
                int retVal = (int) NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_GETSELCOUNT, 0, 0);
                return retVal;
            }
            catch (Win32Exception)
            {
                return LB_ERR;
            }
        }

        /// <summary>
        ///   Uses SendMessage to get a collection of all items in a ListBox
        /// </summary>
        /// <param name="windowHandle"> Handle to Listbox </param>
        /// <returns> A string collection containing each item in the ListBox </returns>
        internal static Collection<object> GetItemsNative(IntPtr windowHandle)
        {
            try
            {
                int itemCount = GetItemCountNative(windowHandle);
                return GetAllItems(windowHandle, itemCount);
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        ///   Uses SendMessage to select an item in the listbox, deselecting all other items
        /// </summary>
        /// <param name="windowHandle"> handle to listbox </param>
        /// <param name="index"> Zero based index of item to select </param>
        internal static void SelectItemNative(IntPtr windowHandle, int index)
        {
            int sndReturn =
                (int) NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_SETCURSEL, index, 0);
        }

        /// <summary>
        ///   Uses SendMessage to select an item in the listbox, deselecting all other items
        /// </summary>
        /// <param name="windowHandle"> handle to listbox </param>
        /// <param name="itemText"> string to search ListBox for. Case insensitive </param>
        internal static void SelectItemNative(IntPtr windowHandle, string itemText)
        {
            int stringIndex = FindString(windowHandle, itemText);

            int sndReturn =
                (int) NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_SETCURSEL, stringIndex, 0);
        }

        /// <summary>
        ///   Uses SendMessage to deselect an item in the listbox
        /// </summary>
        /// <param name="windowHandle"> handle to listbox </param>
        /// <param name="index"> Zero based index of item to select </param>
        internal static void DeSelectItemNative(IntPtr windowHandle, int index)
        {
            NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_SETSEL, 0, index);
        }

        /// <summary>
        ///   Uses SendMessage to deselect an item in the listbox
        /// </summary>
        /// <param name="windowHandle"> handle to listbox </param>
        /// <param name="itemText"> string to search ListBox for. Case insensitive </param>
        internal static void DeSelectItemNative(IntPtr windowHandle, string itemText)
        {
            //int stringIndex = NativeMethods.SendMessage(windowHandle, (int)ListboxMessages.LB_FINDSTRING, -1, itemText);
            int stringIndex = FindString(windowHandle, itemText);

            NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_SETSEL, 0, stringIndex);
        }

        /// <summary>
        ///   Uses SendMessage to select an item in a multi-select ListBox without deselecting other items
        /// </summary>
        /// <param name="windowHandle"> handle to listbox </param>
        /// <param name="index"> Zero based index of item to select </param>
        internal static void AddSelectedItemNative(IntPtr windowHandle, int index)
        {
            NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_SETSEL, 1, index);
        }

        /// <summary>
        ///   Uses SendMessage to select an item in a multi-select ListBox without deselecting other items
        /// </summary>
        /// <param name="windowHandle"> handle to listbox </param>
        /// <param name="itemText"> string to search ListBox for. Case insensitive </param>
        internal static void AddSelectedItemNative(IntPtr windowHandle, string itemText)
        {
            int stringIndex = FindString(windowHandle, itemText);

            NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_SETSEL, 1, stringIndex);
        }

        /* Util */

        private static Collection<object> GetAllItems(IntPtr windowHandle, int itemCount)
        {
            StringBuilder sb = new StringBuilder();
            Collection<object> returnCollection = new Collection<object>();

            for (int i = 0; i < itemCount - 1; i++)
            {
                NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_GETTEXT, i, sb);
                returnCollection.Add(sb.ToString());
                sb.Clear();
            }

            return returnCollection;
        }

        private static int FindString(IntPtr windowHandle, string itemText)
        {
            return NativeMethods.SendMessage(windowHandle, (int) ListboxMessages.LB_FINDSTRING, -1, itemText);
        }
    }
}